package com.ruoyi.app.controller;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.app.annotation.AppSecurity;
import com.ruoyi.app.domain.OfflineReq;
import com.ruoyi.app.service.TrialHandler;
import com.ruoyi.app.util.ReqMsg;
import com.ruoyi.app.util.RspMsg;
import com.ruoyi.bizsys.domain.*;
import com.ruoyi.bizsys.service.*;
import com.ruoyi.bizsys.utils.BizConstants;
import com.ruoyi.bizsys.vo.MonnifyReservedAccount;
import com.ruoyi.business.component.RepaymentMqSendService;
import com.ruoyi.business.domain.GetRepaymentPageReq;
import com.ruoyi.business.service.*;
import com.ruoyi.business.util.BigDecimalConvertUtil;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.enums.RspEnmu;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.Func;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.extdata.service.IExternalApiService;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysDictDataService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

@Api("还款接口")
@RestController
@Slf4j
@RequestMapping("/repayment")
public class RepaymentController extends BaseController {

    @Autowired
    private ILoanIouService iLoanIouService;

    @Autowired
    private IBRepaymentService iBRepaymentService;

    @Autowired
    IExtMonnifyOrderService iExtMonnifyOrderService;

    @Autowired
    IExternalApiService iExternalApiService;

    @Autowired
    IBExtMonnifyOrderService iBExtMonnifyOrderService;

    @Autowired
    IRealNameAuthService iRealNameAuthService;

    @Autowired
    IBLoanInfoService iBLoanInfoService;

    @Autowired
    IRepaymentOrderService repaymentOrderService;

    @Autowired
    RedisCache redisCache;

    @Autowired
    ICustBankCardService custBankCardService;

    @Autowired
    IBankCardService bankCardService;

    @Autowired
    ISysConfigService iSysConfigService;
    @Autowired
    ICustBindCardLogService custBindCardLogService;
    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    QuickRepayService quickRepayService;

    @Autowired
    ISysDictDataService iSysDictDataService;

    @Autowired
    IRepaymentService repaymentService;

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;
    @Autowired
    ICustTransactionSettingService custTransactionSettingService;
    @Autowired
    TrialHandler trialHandler;

    @Autowired
    ILoanDeferredOrderService loanDeferredOrderService;

    @Autowired
    ILoanIouDeferredService loanIouDeferredService;
    @Autowired
    IMonnifyRepaymentService monnifyRepaymentService;

    @Autowired
    ICustVaService custVaService;

    @Autowired
    IDoRepaymentLastService doRepaymentLastService;

    @Autowired
    IBLoanInfoService bLoanInfoService;

    @Autowired
    RepaymentMqSendService repaymentMqService;

    private final static List<String> TRANS_STATUS_LIST = Arrays.asList("2", "3", "9");

    /**
     * 创建ussd还款方式
     */
    @PostMapping("/createUSSD")
    @AppSecurity
    @ApiOperation("创建ussd还款方式")
    @Log(title = "创建ussd还款方式", businessType = BusinessType.INSERT)
    public RspMsg createUSSD(@RequestBody ReqMsg reqMsg) {

        //输入参数 loanSerialNo
        //Gson gson = new Gson();
        RepaymentOrder repaymentOrder = JSON.parseObject(reqMsg.getData().toString(), RepaymentOrder.class);
        //RepaymentOrder repaymentOrder = JSON.parseObject(reqMsg.getData().toString(), RepaymentOrder.class);
        log.info("请求data：{}", JSON.toJSONString(repaymentOrder));


        //校验参数
        if (repaymentOrder.getLoanSerialNo() == null || StringUtils.isBlank(repaymentOrder.getLoanSerialNo())) {
            return RspMsg.fail(RspEnmu.PARAM_CANNOT_NULL);
        }

        LoanIou loanIou = new LoanIou();
        loanIou.setLoanSerialNo(repaymentOrder.getLoanSerialNo());
        loanIou.setState(UserConstants.BUSINESS_NORMAL);
        List<LoanIou> loanIous = iLoanIouService.selectLoanIouList(loanIou);

        if (loanIous == null || loanIous.size() == 0 || loanIous.get(0).getIouStatus() == 1) {
            return RspMsg.fail(RspEnmu.EXTERNAL_API_RSP_FALSE);
        }

        //验证成功
        return RspMsg.ok(iBRepaymentService.createUSSD(loanIous.get(0)));
    }

    /**
     * 通过银行生成ussdpayment编号
     */
    @PostMapping("/getUssdpaymentForBank")
    @AppSecurity
    @ApiOperation("通过银行生成ussdpayment编号")
    @Log(title = "通过银行生成ussdpayment编号", businessType = BusinessType.GET)
    public RspMsg getUssdpaymentForBank(@RequestBody ReqMsg reqMsg) {

        //输入参数paymentReference、AccountDetailsBankCode

        //Gson gson = new Gson();
        ExtMonnifyOrder extMonnifyOrder = JSON.parseObject(reqMsg.getData().toString(), ExtMonnifyOrder.class);
        //ExtMonnifyOrder extMonnifyOrder = gson.fromJson(reqMsg.getData().toString(), ExtMonnifyOrder.class);
        log.info("请求data：{}", JSON.toJSONString(extMonnifyOrder));

        //参数是否为空
        if (extMonnifyOrder.getPaymentReference() == null || StringUtils.isBlank(extMonnifyOrder.getPaymentReference())
                || extMonnifyOrder.getAccountDetailsBankCode() == null || StringUtils.isBlank(extMonnifyOrder.getAccountDetailsBankCode())) {
            return RspMsg.fail(RspEnmu.PARAM_CANNOT_NULL);
        }

        //参数是否合法
        ExtMonnifyOrder extMonnifyOrder1 = new ExtMonnifyOrder();
        extMonnifyOrder1.setPaymentReference(extMonnifyOrder.getPaymentReference());
        extMonnifyOrder1.setState(UserConstants.BUSINESS_NORMAL);
        extMonnifyOrder1.setType(BizConstants.MONNFIY_ORDER_TYPE_USSD);
        List<ExtMonnifyOrder> extMonnifyOrders = iExtMonnifyOrderService.selectExtMonnifyOrderList(extMonnifyOrder1);

        if (extMonnifyOrders == null || extMonnifyOrders.size() == 0) {
            return RspMsg.fail(RspEnmu.EXTERNAL_API_RSP_FALSE);
        }

        //验证成功
        String ussdPayment = iBRepaymentService.getUssdpaymentForBank(extMonnifyOrders.get(0).getTransactionReference(), extMonnifyOrder.getAccountDetailsBankCode());

        Map<String, String> map = new HashMap<>();
        map.put("ussdPayment", ussdPayment);

        return RspMsg.ok(map);
    }

    /**
     * checkTransferToUs还款方式
     * 检查钱包是否够扣除全部金额，够的话直接结算，返回true
     * 其他返回false,不处理，等待下一个接口处理
     */
    @PostMapping("/checkTransferToUs")
    @AppSecurity
    @ApiOperation("checkTransferToUs-TransferToUs还款方式")
    @Log(title = "checkTransferToUs-ransferToUs还款方式", businessType = BusinessType.INSERT)
    public RspMsg checkTransferToUs(@RequestBody ReqMsg reqMsg) {
        JSONObject dataJson = new JSONObject();
        if (Func.isNotEmpty(reqMsg.getData())) {
            dataJson = JSONObject.parseObject(reqMsg.getData().toString());
        }
        if (null == dataJson.get("loanSerialNo") || StringUtils.isBlank(dataJson.get("loanSerialNo").toString())) {
            throw new BusinessException(RspEnmu.PARAM_CANNOT_NULL);
        }
        // 获取是否使用了钱包
        if (null == dataJson.get("useWallet") || StringUtils.isBlank(dataJson.get("useWallet").toString())) {
            throw new BusinessException(RspEnmu.PARAM_CANNOT_NULL);
        }
        LoanIou loanIou = getLoanIou(dataJson.get("loanSerialNo").toString());
        BigDecimal minPay = LoanIou.calculationOverdueAmount(loanIou);
        // 先查询钱包可用余额，
        BigDecimal leftWalletAmt = doRepaymentLastService.getWalletAmount(loanIou.getCustNo());
        if (leftWalletAmt.compareTo(minPay) < 0) {
            log.info("查询钱包余额小于minPay,{},{}", leftWalletAmt, minPay);
            return RspMsg.ok(false);
        }
        JSONObject amtWalletObj = doRepaymentLastService.getAmtWallet(minPay, loanIou.getCustNo(), loanIou.getLoanSerialNo(), false);
        BigDecimal amtWallet = amtWalletObj.getBigDecimal("amtWallet");
        String walletNo = amtWalletObj.getString("walletOrderNo");
        if (amtWallet.compareTo(minPay) == 0) {
            // 钱包余额
            log.info("钱包余额够支付的延期费用,{},{}", amtWallet, minPay);
            // 创建repayMentOrder
            RepaymentOrder repaymentOrder = bLoanInfoService.createRepaymentOrderRepayAllWalletNoSuccess(
                    loanIou,
                    BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERAT_WALLET,
                    "Active", amtWallet, walletNo);
            if (null != repaymentOrder) {
                try {
                    SendResult sendResult = repaymentMqService.selfWalletForAllPayRepaymentMq(loanIou, repaymentOrder);
                    if (!sendResult.getSendStatus().equals(SendStatus.SEND_OK)) {
                        doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
                    }
                } catch (Exception e) {
                    doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
                    throw new RuntimeException(e);
                }

                return RspMsg.ok(true);
            }
        }else{
            doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
        }
        return RspMsg.ok(false);

    }

    /**
     * 创建TransferToUs还款方式
     */
    @PostMapping("/createTransferToUs")
    @AppSecurity
    @ApiOperation("创建TransferToUs还款方式")
    @Log(title = "创建TransferToUs还款方式", businessType = BusinessType.INSERT)
    public RspMsg createTransferToUs(@RequestBody ReqMsg reqMsg) {
        RepaymentOrder repaymentOrder = JSON.parseObject(reqMsg.getData().toString(), RepaymentOrder.class);
        log.info("请求data：{}", JSON.toJSONString(repaymentOrder));
        //校验参数
        if (StringUtils.isBlank(repaymentOrder.getLoanSerialNo())) {
            return RspMsg.fail(RspEnmu.PARAM_CANNOT_NULL);
        }
        LoanIou loanIou = getLoanIou(repaymentOrder.getLoanSerialNo());

        // todo 需要修改查询
        // 查询 Monnify和Paystack的VA 返回排序的最小的，且银行是启用的（sys_dict_data）
        MonnifyReservedAccount monnifyReservedAccount = custVaService.getVaReservedAccount(loanIou.getCustNo());

        if (null == monnifyReservedAccount) {
            return RspMsg.fail(RspEnmu.MONNIFY_TRANSTOUS_NO_VA_ACCOUNT);
        }

        //monnifyRepaymentService.initRepaymentOrder(loanIou);
        return RspMsg.ok(monnifyReservedAccount);
    }


    private MonnifyReservedAccount getMonnifyReservedAccount(JSONObject dataJson) {
        LoanIou loanIou = getLoanIou(dataJson.get("loanSerialNo").toString());
        BigDecimal minPay = LoanIou.calculationOverdueAmount(loanIou);
        JSONObject amtWalletObj = doRepaymentLastService.getAmtWallet(minPay, loanIou.getCustNo(), loanIou.getLoanSerialNo(), false);
        BigDecimal amtWallet = amtWalletObj.getBigDecimal("amtWallet");
        String walletNo = amtWalletObj.getString("walletOrderNo");
        if (amtWallet.compareTo(BigDecimal.ZERO) > 0) {
            log.info("钱包余额部分还款,");
            // 创建钱包支付的repaymentOrder 状态为5 进行冲账
            RepaymentOrder repaymentOrderWallet = repaymentService.createRepaymentOrderForfWalletNotAll(BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERAT_WALLET, amtWallet, walletNo, loanIou);
            if (null != repaymentOrderWallet) {
                // 钱包支付全额还款，不需要等待卡支付回调进行冲账，06-15有沟通
                SendResult sendResult = repaymentMqService.selfWalletForAllPayRepaymentMq(loanIou, repaymentOrderWallet);
                if (!sendResult.getSendStatus().equals(SendStatus.SEND_OK)) {
                    doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
                }
            } else {
                doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
            }
        }
        MonnifyReservedAccount monnifyReservedAccount = custVaService.getVaReservedAccount(loanIou.getCustNo());

        monnifyRepaymentService.initRepaymentOrder(loanIou);
        return monnifyReservedAccount;
    }

    /**
     * monnify-TransferToUs-repay
     */
    @PostMapping("/monnify/transferToUs")
    @AppSecurity
    @ApiOperation("monnify-TransferToUs-repay")
    @Log(title = "monnify-TransferToUs-repay", businessType = BusinessType.INSERT)
    public RspMsg monnifyTransferToUs(@RequestBody ReqMsg reqMsg) {
//repayment/monnify/transferToUs
        RepaymentOrder repaymentOrder = JSON.parseObject(reqMsg.getData().toString(), RepaymentOrder.class);
        log.info("请求data：{}", JSON.toJSONString(repaymentOrder));

        //校验参数
        if (StringUtils.isBlank(repaymentOrder.getLoanSerialNo())) {
            return RspMsg.fail(RspEnmu.PARAM_CANNOT_NULL);
        }
//        JSONObject dataJson = new JSONObject();
//        if (Func.isNotEmpty(reqMsg.getData())) {
//            dataJson = JSONObject.parseObject(reqMsg.getData().toString());
//        }
//        // 获取是否使用了钱包
//        if (null != dataJson.get("useWallet") && !StringUtils.isBlank(dataJson.get("useWallet").toString())) {
//            // 使用了钱包
//            LoanIou loanIou = getLoanIou(dataJson.get("loanSerialNo").toString());
//            BigDecimal minPay = LoanIou.calculationOverdueAmount(loanIou);
//            JSONObject amtWalletObj = doRepaymentLastService.getAmtWallet(minPay, loanIou.getCustNo(), loanIou.getLoanSerialNo(), false);
//            BigDecimal amtWallet = amtWalletObj.getBigDecimal("amtWallet");
//            String walletNo = amtWalletObj.getString("walletOrderNo");
//            if (amtWallet.compareTo(BigDecimal.ZERO) > 0) {
//                log.info("钱包余额部分还款,");
//                // 创建钱包支付的repaymentOrder 状态为5 进行冲账
//                RepaymentOrder repaymentOrderWallet
//                        = repaymentService.createRepaymentOrderForfWalletNotAll(BizConstants.LOAN_REPAYMENT_ORDER_TYPE_TRANSFERTOUS_WALLET, amtWallet, walletNo, loanIou);
//                if (null != repaymentOrderWallet) {
//                    // 钱包支付全额还款，不需要等待卡支付回调进行冲账，06-15有沟通
//                    try {
//                        SendResult sendResult = repaymentMqService.selfWalletForAllPayRepaymentMq(loanIou, repaymentOrderWallet);
//                        if (!sendResult.getSendStatus().equals(SendStatus.SEND_OK)) {
//                            doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
//                        }
//                    } catch (Exception e) {
//                        doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
//                        throw new RuntimeException(e);
//                    }
//                } else {
//                    doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
//                }
//            }
//        }

        LoanIou loanIou = getLoanIou(repaymentOrder.getLoanSerialNo());

        List<MonnifyReservedAccount> monnifyReservedAccounts = custVaService.getAllVaReservedAccounts(loanIou.getCustNo());
        if (null == monnifyReservedAccounts || monnifyReservedAccounts.size() == 0) {
            return RspMsg.fail(RspEnmu.MONNIFY_TRANSTOUS_NO_VA_ACCOUNT);
        }

        // monnifyRepaymentService.initRepaymentOrder(loanIou);

        return RspMsg.ok(monnifyReservedAccounts);
    }

    private LoanIou getLoanIou(String loanSerialNo) {
        QueryWrapper<LoanIou> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("loan_serial_no", loanSerialNo).eq("state", UserConstants.BUSINESS_NORMAL).select("cust_no", "loan_serial_no", "iou_status", "loan_principal", "repaid_principal", "loan_interest", "repaid_interest", "service_fee", "repaid_service_fee", "late_fee", "repaid_late_fee", "fee_remission_amt", "reduce_amt").last("order by id desc limit 1");
        LoanIou loanIou = iLoanIouService.getOne(queryWrapper);
        if (loanIou == null || loanIou.getIouStatus() == 1) {
            throw new BusinessException(RspEnmu.LOAN_IOU_NOT_NEED_TO_BE_REPAID);
        }
        return loanIou;
    }

    /**
     * 提交TransferToUs还款方式
     */
    @PostMapping("/submitTransferToUs")
    @AppSecurity
    @ApiOperation("提交TransferToUs还款方式")
    @Log(title = "提交TransferToUs还款方式", businessType = BusinessType.INSERT)
    public RspMsg submitTransferToUs(@RequestBody ReqMsg reqMsg) {

        if (checkTime()) {
            return RspMsg.fail(RspEnmu.SYSTEM_MAINTENANCE);
        }

        //输入参数 accountReference
        //Gson gson = new Gson();
        //RepaymentTransfer repaymentTransfer = gson.fromJson(reqMsg.getData().toString(), RepaymentTransfer.class);
        //repaymentTransfer.setPayTime(Date);
        RepaymentTransfer repaymentTransfer = JSON.parseObject(reqMsg.getData().toString(), RepaymentTransfer.class);
        log.info("请求data：{}", JSON.toJSONString(repaymentTransfer));


        //校验参数
        if (repaymentTransfer.getCustNo() == null || StringUtils.isBlank(repaymentTransfer.getCustNo())
                || repaymentTransfer.getLoanSerialNo() == null || StringUtils.isBlank(repaymentTransfer.getLoanSerialNo())
                || repaymentTransfer.getAmount() == null || repaymentTransfer.getAmount().doubleValue() <= 0
                || repaymentTransfer.getPayTime() == null) {
            return RspMsg.fail(RspEnmu.PARAM_CANNOT_NULL);
        }

//        //判断当前是否正在轮询
//        String cacheObject = redisCache.getCacheObject(BizConstants.TRANSFER_TO_US_THREAD + repaymentTransfer.getCustNo());
//        if (cacheObject != null && !StringUtils.isBlank(cacheObject)) {
//            return RspMsg.fail(RspEnmu.DUPLICATE_SUBMISSION);
//        }

        //验证成功
        iBRepaymentService.submitTransferToUs(repaymentTransfer);

        return RspMsg.ok();
    }

    /**
     * 创建card还款方式
     */
    @PostMapping("/createCard")
    @AppSecurity
    @ApiOperation("创建card还款方式")
    @Log(title = "创建card还款方式", businessType = BusinessType.INSERT)
    public RspMsg createCard(@RequestBody ReqMsg reqMsg) {

        //输入参数 loanSerialNo
        //Gson gson = new Gson();
        //RepaymentOrder repaymentOrder = gson.fromJson(reqMsg.getData().toString(), RepaymentOrder.class);
        RepaymentOrder repaymentOrder = JSON.parseObject(reqMsg.getData().toString(), RepaymentOrder.class);
        log.info("请求data：{}", JSON.toJSONString(repaymentOrder));


        //校验参数
        if (repaymentOrder.getLoanSerialNo() == null || StringUtils.isBlank(repaymentOrder.getLoanSerialNo())) {
            return RspMsg.fail(RspEnmu.PARAM_CANNOT_NULL);
        }

        LoanIou loanIou = new LoanIou();
        loanIou.setLoanSerialNo(repaymentOrder.getLoanSerialNo());
        loanIou.setState(UserConstants.BUSINESS_NORMAL);
        List<LoanIou> loanIous = iLoanIouService.selectLoanIouList(loanIou);

        if (loanIous == null || loanIous.size() == 0 || loanIous.get(0).getIouStatus() == 1) {
            return RspMsg.fail(RspEnmu.EXTERNAL_API_RSP_FALSE);
        }

        //验证成功
        JSONObject card = iBRepaymentService.createCard(loanIous.get(0));

        return RspMsg.ok(card);
    }

    /**
     * 提交ussd还款方式
     */
    @PostMapping("/submitUssd")
    @AppSecurity
    @ApiOperation("提交ussd还款方式")
    @Log(title = "提交ussd还款方式", businessType = BusinessType.INSERT)
    public RspMsg submitUssd(@RequestBody ReqMsg reqMsg) {

        //输入参数paymentReference

        if (checkTime()) {
            return RspMsg.fail(RspEnmu.SYSTEM_MAINTENANCE);
        }

        //Gson gson = new Gson();
        ExtMonnifyOrder extMonnifyOrder = JSON.parseObject(reqMsg.getData().toString(), ExtMonnifyOrder.class);
        //ExtMonnifyOrder extMonnifyOrder = gson.fromJson(reqMsg.getData().toString(), ExtMonnifyOrder.class);
        log.info("请求data：{}", JSON.toJSONString(extMonnifyOrder));

        //参数是否为空
        if (extMonnifyOrder.getPaymentReference() == null || StringUtils.isBlank(extMonnifyOrder.getPaymentReference())) {
            return RspMsg.fail(RspEnmu.PARAM_CANNOT_NULL);
        }

        //判断当前是否正在轮询
        String cacheObject = redisCache.getCacheObject(BizConstants.TRANSACTION_THREAD + extMonnifyOrder.getPaymentReference());
        if (cacheObject != null && !StringUtils.isBlank(cacheObject)) {
            return RspMsg.fail(RspEnmu.DUPLICATE_SUBMISSION);
        }

        //参数是否合法
        ExtMonnifyOrder extMonnifyOrder1 = new ExtMonnifyOrder();
        extMonnifyOrder1.setPaymentReference(extMonnifyOrder.getPaymentReference());
        extMonnifyOrder1.setState(UserConstants.BUSINESS_NORMAL);
        extMonnifyOrder1.setType(BizConstants.MONNFIY_ORDER_TYPE_USSD);
        List<ExtMonnifyOrder> extMonnifyOrders = iExtMonnifyOrderService.selectExtMonnifyOrderList(extMonnifyOrder1);

        if (extMonnifyOrders == null || extMonnifyOrders.size() == 0) {
            return RspMsg.fail(RspEnmu.EXTERNAL_API_RSP_FALSE);
        }

        //验证成功
        iBRepaymentService.submitUssd(extMonnifyOrders.get(0).getPaymentReference(), extMonnifyOrders.get(0).getTransactionReference());

        return RspMsg.ok();
    }

    /**
     * 提交card还款方式
     */
    @PostMapping("/submitCard")
    @AppSecurity
    @ApiOperation("提交card还款方式")
    @Log(title = "提交card还款方式", businessType = BusinessType.INSERT)
    public RspMsg submitCard(@RequestBody ReqMsg reqMsg) {

        //输入参数paymentReference、transactionReference

        if (checkTime()) {
            return RspMsg.fail(RspEnmu.SYSTEM_MAINTENANCE);
        }

        //Gson gson = new Gson();
        ExtMonnifyOrder extMonnifyOrder = JSON.parseObject(reqMsg.getData().toString(), ExtMonnifyOrder.class);
        //ExtMonnifyOrder extMonnifyOrder = gson.fromJson(reqMsg.getData().toString(), ExtMonnifyOrder.class);
        log.info("请求data：{}", JSON.toJSONString(extMonnifyOrder));

        //参数是否为空
        if (extMonnifyOrder.getPaymentReference() == null || StringUtils.isBlank(extMonnifyOrder.getPaymentReference())
                || extMonnifyOrder.getTransactionReference() == null || StringUtils.isBlank(extMonnifyOrder.getTransactionReference())) {
            return RspMsg.fail(RspEnmu.PARAM_CANNOT_NULL);
        }

        //判断当前是否正在轮询
        String cacheObject = redisCache.getCacheObject(BizConstants.TRANSACTION_THREAD + extMonnifyOrder.getPaymentReference());
        if (cacheObject != null && !StringUtils.isBlank(cacheObject)) {
            return RspMsg.fail(RspEnmu.DUPLICATE_SUBMISSION);
        }

        RepaymentOrder repaymentOrderSelect = new RepaymentOrder();
        repaymentOrderSelect.setActionType(BizConstants.LOAN_REPAYMENT_ORDER_TYPE_CARD);
        repaymentOrderSelect.setState(UserConstants.BUSINESS_NORMAL);
        repaymentOrderSelect.setRepayStatus(2);
        repaymentOrderSelect.setRepaymentNo(extMonnifyOrder.getPaymentReference());
        List<RepaymentOrder> repaymentOrders = repaymentOrderService.selectRepaymentOrderList(repaymentOrderSelect);
        if (repaymentOrders == null || repaymentOrders.size() == 0) {
            return RspMsg.fail(RspEnmu.EXTERNAL_API_RSP_FALSE);
        }

        //验证成功
        iBRepaymentService.submitCard(repaymentOrders.get(0), extMonnifyOrder.getPaymentReference(), extMonnifyOrder.getTransactionReference());

        return RspMsg.ok();
    }

    /**
     * 进入ussd、card、tts页面
     */
    @PostMapping("/getRepaymentPage")
    @AppSecurity
    @ApiOperation("进入ussd、card、tts页面")
    @Log(title = "进入ussd、card、tts页面", businessType = BusinessType.INSERT)
    public RspMsg getRepaymentPage(@RequestBody ReqMsg reqMsg) {

        //输入参数type、loanSerialNo
        JSONObject jsonObject = new JSONObject();

        //Gson gson = new Gson();
        //GetRepaymentPageReq getRepaymentPageReq = gson.fromJson(reqMsg.getData().toString(), GetRepaymentPageReq.class);
        GetRepaymentPageReq getRepaymentPageReq = JSON.parseObject(reqMsg.getData().toString(), GetRepaymentPageReq.class);
        log.info("请求data：{}", JSON.toJSONString(getRepaymentPageReq));
        checkAttribute(getRepaymentPageReq);

        //QuickRepay校验
        if (getRepaymentPageReq.getType().equals(BizConstants.LOAN_REPAYMENT_ORDER_TYPE_QUICK) && Func.isNotEmpty(getRepaymentPageReq.getCardNumber())) {
            String redisKey = BizConstants.LOAN_REPAY_CARD + getRepaymentPageReq.getLoanSerialNo();
            Object cacheObject = redisCache.getCacheObject(redisKey);
            boolean open = Func.isEmpty(cacheObject);
            jsonObject.put("isOpen", open);
            //jsonObject.put("isPopup",open);
            return RspMsg.ok(jsonObject);
        }

        //参数是否为空
        if (!getRepaymentPageReq.getType().equals(BizConstants.LOAN_REPAYMENT_ORDER_TYPE_USSD) && !getRepaymentPageReq.getType().equals(BizConstants.LOAN_REPAYMENT_ORDER_TYPE_CARD) && !getRepaymentPageReq.getType().equals(BizConstants.LOAN_REPAYMENT_ORDER_TYPE_TTS) && !getRepaymentPageReq.getType().equals(BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERATE)) {
            return RspMsg.fail(RspEnmu.ILLEGAL_ARGUMENT);
        }

        if (checkTime()) {
            jsonObject.put("isOpen", false);
            //jsonObject.put("isPopup",false);
            return RspMsg.ok(jsonObject);
        }

//        RepaymentOrder repaymentOrderSelect1 = new RepaymentOrder();
//        repaymentOrderSelect1.setLoanSerialNo(getRepaymentPageReq.getLoanSerialNo());
//        repaymentOrderSelect1.setState(UserConstants.BUSINESS_NORMAL);
//        repaymentOrderSelect1.setRepayStatus(5);
//        List<RepaymentOrder> repaymentOrders1 = repaymentOrderService.selectRepaymentOrderList(repaymentOrderSelect1);
//
//        if(repaymentOrders1!=null && repaymentOrders1.size()>0){
//            for (int i = 0;i<repaymentOrders1.size();i++){
//                if(!repaymentOrders1.get(i).getActionType().equals(getRepaymentPageReq.getType())){
//                    jsonObject.put("isPopup",true);
//                    break;
//                }else{
//                    jsonObject.put("isPopup",false);
//                }
//            }
//        }else{
//            jsonObject.put("isPopup",false);
//        }

        List<RepaymentOrder> repaymentOrders = iBRepaymentService.getToActionTypeAndLoanSerialNo(getRepaymentPageReq.getType(), getRepaymentPageReq.getLoanSerialNo());

        if (repaymentOrders != null && repaymentOrders.size() > 0) {
            String redisName = "";
            if (getRepaymentPageReq.getType().equals(BizConstants.LOAN_REPAYMENT_ORDER_TYPE_USSD) || getRepaymentPageReq.getType().equals(BizConstants.LOAN_REPAYMENT_ORDER_TYPE_CARD)) {
                redisName = BizConstants.TRANSACTION_THREAD + repaymentOrders.get(0).getRepaymentNo();
            } else if (getRepaymentPageReq.getType().equals(BizConstants.LOAN_REPAYMENT_ORDER_TYPE_TTS)) {
                redisName = BizConstants.TRANSFER_TO_US_THREAD + repaymentOrders.get(0).getCustNo();
            }

            //判断当前是否正在轮询
            String cacheObject = redisCache.getCacheObject(redisName);
            if (cacheObject != null) {
                jsonObject.put("isOpen", false);
            } else {
                jsonObject.put("isOpen", true);
            }
        } else {
            jsonObject.put("isOpen", true);
        }


        return RspMsg.ok(jsonObject);

    }

    /**
     * 提交线下还款方式
     */
    @PostMapping("/submitOffline")
    @ApiOperation("提交线下还款方式")
    @Log(title = "提交线下还款方式", businessType = BusinessType.INSERT)
    public RspMsg submitOffline(@RequestBody ReqMsg reqMsg) {

        //输入参数phone_number、pay_time(还款日期)、firstName，lastName、amount

        //Gson gson = new Gson();
        OfflineReq offlineReq = JSON.parseObject(reqMsg.getData().toString(), OfflineReq.class);
        log.info("请求data：{}", JSON.toJSONString(offlineReq));

        checkAttribute(offlineReq);

        if (offlineReq.getAmount().doubleValue() <= 0) {
            //金额不能小于等于0
            return RspMsg.fail(RspEnmu.PARAM_CANNOT_NULL);
        }

        //查询该用户是否存在
        RealNameAuth realNameAuth = new RealNameAuth();
        realNameAuth.setPhoneNumber(offlineReq.getPhoneNumber());
        realNameAuth.setState("1");
        List<RealNameAuth> realNameAuths = iRealNameAuthService.selectRealNameAuthList(realNameAuth);
        if (realNameAuths == null || realNameAuths.size() == 0) {
            //用户不存在
            return RspMsg.fail(RspEnmu.CUSTOMER_IS_NOT_EXISTS);
        }

        for (int i = 0; i < realNameAuths.size(); i++) {

            String[] basisNames = new String[]{offlineReq.getFirstName().toUpperCase(), offlineReq.getLastName().toUpperCase()};
            List<String> accountNames = Arrays.asList(new String[]{realNameAuths.get(i).getFirstName().toUpperCase(), realNameAuths.get(i).getLastName().toUpperCase()});
            int matches = 0;
            for (int j = 0; j < basisNames.length; j++) {
                if (accountNames.contains(basisNames[j])) {
                    matches++;
                }
            }
            //需要配对的basisName没有全部命中 则校验失败
            if (matches != basisNames.length) {
                return RspMsg.fail(RspEnmu.REAL_NAME_CHECK_FAILED_BY_NAME);
            }
        }

        //查询用户是否存在借据
        List<LoanIou> loanIouList = iBLoanInfoService.getFirstByCustNo(realNameAuths.get(0).getCustNo());
        if (loanIouList == null || loanIouList.size() == 0) {
            //用户不存在借据
            return RspMsg.fail(RspEnmu.CUST_NO_LOAN);
        }

        //验证成功
        LoanIou loanIou1 = new LoanIou();
        BeanUtils.copyBeanProp(loanIou1, loanIouList.get(0));

        RepaymentOrder repaymentOrder = repaymentService.getMaxSuccessDate(loanIouList.get(0).getLoanSerialNo());

        LoanIou loanIou = iBRepaymentService.submitOffline(loanIouList.get(0), offlineReq.getPayTime(), offlineReq.getAmount(), JSON.toJSONString(offlineReq));
        String loanIouStatus = iSysDictDataService.selectDictLabel("loan_iou_status", loanIou.getIouStatus() + "");

        Map<String, Object> map = new HashMap<>();

        //冲账前数据
        Map<String, Object> beforeLoanIou = new HashMap<>();
        beforeLoanIou.put("loanPrincipal", loanIou1.getLoanPrincipal());
        beforeLoanIou.put("repaidPrincipal", loanIou1.getRepaidPrincipal());
        beforeLoanIou.put("serviceFee", loanIou1.getServiceFee());
        beforeLoanIou.put("repaidServiceFee", loanIou1.getRepaidServiceFee());
        beforeLoanIou.put("loanInterest", loanIou1.getLoanInterest());
        beforeLoanIou.put("repaidInterest", loanIou1.getRepaidInterest());
        beforeLoanIou.put("lateFee", loanIou1.getLateFee());
        beforeLoanIou.put("repaidLateFee", loanIou1.getRepaidLateFee());
        beforeLoanIou.put("feeRemissionAmt", loanIou1.getFeeRemissionAmt());
        map.put("beforeLoanIou", beforeLoanIou);

        //冲账后数据
        Map<String, Object> afterLoanIou = new HashMap<>();
        afterLoanIou.put("loanPrincipal", loanIou.getLoanPrincipal());
        afterLoanIou.put("repaidPrincipal", loanIou.getRepaidPrincipal());
        afterLoanIou.put("serviceFee", loanIou.getServiceFee());
        afterLoanIou.put("repaidServiceFee", loanIou.getRepaidServiceFee());
        afterLoanIou.put("loanInterest", loanIou.getLoanInterest());
        afterLoanIou.put("repaidInterest", loanIou.getRepaidInterest());
        afterLoanIou.put("lateFee", loanIou.getLateFee().setScale(4, RoundingMode.HALF_UP));
        afterLoanIou.put("repaidLateFee", loanIou.getRepaidLateFee());
        afterLoanIou.put("feeRemissionAmt", loanIou.getFeeRemissionAmt());
        map.put("afterLoanIou", afterLoanIou);

        //变动冲账记录
        Map<String, Object> repaymentInfo = new HashMap<>();
        repaymentInfo.put("repaidPrincipal", loanIou.getRepaidPrincipal().subtract(loanIou1.getRepaidPrincipal()));
        repaymentInfo.put("repaidServiceFee", loanIou.getRepaidServiceFee().subtract(loanIou1.getRepaidServiceFee()));
        repaymentInfo.put("repaidInterest", loanIou.getRepaidInterest().subtract(loanIou1.getRepaidInterest()));
        repaymentInfo.put("repaidLateFee", loanIou.getRepaidLateFee().subtract(loanIou1.getRepaidLateFee()));
        repaymentInfo.put("feeRemissionAmt", loanIou.getFeeRemissionAmt().subtract(loanIou1.getFeeRemissionAmt().setScale(4, RoundingMode.HALF_UP)));
        map.put("repaymentInfo", repaymentInfo);

        map.put("name", realNameAuths.get(0).getFirstName() + " " + realNameAuths.get(0).getMiddleName() + " " + realNameAuths.get(0).getLastName());
        map.put("phone", realNameAuths.get(0).getPhoneNumber());
        map.put("loanSerialNo", loanIouList.get(0).getLoanSerialNo());
        map.put("payTime", DateUtils.dateTime(offlineReq.getPayTime(), "yyyy/MM/dd"));
        map.put("writeTime", DateUtils.dateTimeNow("yyyy/MM/dd"));
        map.put("repayDate", loanIouList.get(0).getRepayDate());


        map.put("latelyRepayDate", repaymentOrder != null && repaymentOrder.getPayTime() != null ? DateUtils.dateTime(repaymentOrder.getPayTime(), "yyyy/MM/dd") : "");
        map.put("loanIouStatus", loanIouStatus);

        return RspMsg.ok(map);
    }

    public static boolean checkTime() {
        Date startOfDate = Calendar.getInstance().getTime();
        Calendar calendar2 = Calendar.getInstance();
        calendar2.set(calendar2.get(Calendar.YEAR), calendar2.get(Calendar.MONTH), calendar2.get(Calendar.DAY_OF_MONTH),
                23, 30, 00);
        Date endOfDate = calendar2.getTime();

        //如果当前时间小于23点之前
        if (startOfDate.before(endOfDate)) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * t-pin的还款试算，22-06-10新增一个前端flag,根据这个flag去判断走什么类的试算
     *
     * @param reqMsg
     * @return
     */
    @AppSecurity
    @PostMapping("/trial")
    @ApiOperation("还款试算")
    @Log(title = "还款试算", businessType = BusinessType.GET)
    public RspMsg repaymentTrial(@RequestBody ReqMsg reqMsg) throws Exception {
        JSONObject dataJson = new JSONObject();
        if (Func.isNotEmpty(reqMsg.getData())) {
            dataJson = JSONObject.parseObject(reqMsg.getData().toString());
        }
        if (null == dataJson.get("serviceFlag") || StringUtils.isBlank(dataJson.get("serviceFlag").toString())) {
            throw new BusinessException(RspEnmu.PARAM_CANNOT_NULL);
        }
        if (Func.hasEmpty(dataJson.get("loanSerialNo"))) {
            throw new BusinessException(RspEnmu.PARAM_CANNOT_NULL);
        }
        if ("deferredRepayService".equals(dataJson.getString("serviceFlag"))) {
            // 检查是否存在延期中的订单
            LoanDeferredOrder loanDeferredOrder = loanDeferredOrderService.getOne(new QueryWrapper<LoanDeferredOrder>()
                    .eq("loan_serial_no", dataJson.getString("loanSerialNo"))
                    .eq("status", LoanDeferredOrder.STATUS_WAIT)
                    .last("limit 1")
            );
            if (null != loanDeferredOrder) {
                throw new BusinessException(RspEnmu.PRODUCT_DEFERRED_IS_ALREDADY_EXXISTS);
            }
            // 检查当天是否有延期成功的订单
            LoanIouDeferred loanIouDeferred = loanIouDeferredService.getOne(new QueryWrapper<LoanIouDeferred>()
                    .eq("loan_serial_no", dataJson.getString("loanSerialNo"))
                    .apply(true, "TO_DAYS(NOW())-TO_DAYS(create_time) = 0")
                    .last("limit 1")
            );
            if (null != loanIouDeferred) {
                throw new BusinessException(RspEnmu.PRODUCT_DEFERRED_TODAY_IS_HAS_SUCCESS);
            }

        }

        // 获取是否使用了钱包
        if (null == dataJson.get("useWallet") || StringUtils.isBlank(dataJson.get("useWallet").toString())) {
            throw new BusinessException(RspEnmu.PARAM_CANNOT_NULL);
        }
        // 是否只用钱包
        if (null == dataJson.get("isJustWallet") || StringUtils.isBlank(dataJson.get("isJustWallet").toString())) {
           // throw new BusinessException(RspEnmu.PARAM_CANNOT_NULL);
            dataJson.put("isJustWallet",false);
        }
        JSONObject res = trialHandler.getHandle(dataJson.getString("serviceFlag")).handle(dataJson);
        res.put("totalAmount", BigDecimalConvertUtil.convert(res.getBigDecimal("totalAmount")));
        return RspMsg.ok(res);
    }


    @PostMapping("/createOrder")
    @AppSecurity
    @ApiOperation("获取认证url，创建还款订单")
    @Log(title = "获取认证url", businessType = BusinessType.GET)
    public RspMsg creatPay(@Validated @RequestBody ReqMsg reqMsg) {
        //参数转换
        JSONObject dataJson = new JSONObject();
        if (null != reqMsg.getData() && StringUtils.isNotBlank(reqMsg.getData().toString())) {
            dataJson = JSONObject.parseObject(reqMsg.getData().toString());
        }
        // 获取是否使用了钱包
        if (null == dataJson.get("useWallet") || StringUtils.isBlank(dataJson.get("useWallet").toString())) {
            throw new BusinessException(RspEnmu.PARAM_CANNOT_NULL);
        }
        //请求参数校验
        if (null == dataJson.get("loanSerialNo") || StringUtils.isBlank(dataJson.get("loanSerialNo").toString())
                || null == dataJson.get("repaymentAmt") || StringUtils.isBlank(dataJson.get("repaymentAmt").toString())
        ) {
            throw new BusinessException(RspEnmu.PARAM_CANNOT_NULL);
        }

        if (null != dataJson.get("password")) {
            boolean passwordCheck = quickRepayService.isPasswordCheck(getUserId(), dataJson.getString("password"));
            if (!passwordCheck) {
                throw new BusinessException(RspEnmu.T_PASSWORD_ERR);
            }
        }

        if (null != dataJson.get("deferredId") && !StringUtils.isBlank(dataJson.get("deferredId").toString())) {
            // 检查是否存在延期中的订单
            LoanDeferredOrder loanDeferredOrder = loanDeferredOrderService.getOne(new QueryWrapper<LoanDeferredOrder>()
                    .eq("loan_serial_no", dataJson.getString("loanSerialNo"))
                    .eq("status", LoanDeferredOrder.STATUS_WAIT)
                    .last("limit 1")
            );
            if (null != loanDeferredOrder) {
                throw new BusinessException(RspEnmu.TRANSACTION_SERIAL_NO_NOT_EXISTS.getCode(),RspEnmu.PRODUCT_DEFERRED_IS_ALREDADY_EXXISTS.getMessage());
            }
            // 检查延期包有效性
            boolean canBuy = quickRepayService.checkCanBuyDefer(dataJson.getInteger("deferredId"), dataJson.getString("loanSerialNo"));
            if (!canBuy) {
                throw new BusinessException(RspEnmu.PRODUCT_DEFERRED_IS_DOWN);
            }
        }

        JSONObject auth = repaymentService.creatPayOrder(dataJson);

        return RspMsg.ok(auth);
    }



//
//    @PostMapping("/showH5Token")
//    @AppSecurity
//    @ApiOperation("获取打开h5页面的token")
//    @Log(title = "showH5Token", businessType = BusinessType.GET)
//    public RspMsg showH5Token(@Validated @RequestBody ReqMsg reqMsg) {
//        String tokenOnce = BizConstants.TONEK_FOR_H5+Md5Utils.getAndroidNativeMD5(getUserId()+ IdWorker.getId());
//        redisCache.setCacheObject(tokenOnce,getCustNo(),60, TimeUnit.SECONDS);
//        return RspMsg.ok(tokenOnce);
//    }


}